﻿#include "TimeSys.h"
#include <iostream>

// 判断闰年
static bool is_leap(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
// 每月天数
static int month_days(int year, int month) {
    static const int days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
    if (month == 2 && is_leap(year)) return 29;
    return days[month - 1];
}
// 计算从originT到t0的天数
static int days_between(const CalendT& from, const CalendT& to) {
    int days = 0;
    CalendT cur = from;
    while (cur.year < to.year || cur.month < to.month || cur.day < to.day) {
        cur.day++;
        if (cur.day > month_days(cur.year, cur.month)) {
            cur.day = 1;
            cur.month++;
            if (cur.month > 12) {
                cur.month = 1;
                cur.year++;
            }
        }
        days++;
    }
    return days;
}
SOW TimeSys::calend2sow(CalendT t0) {
    BaseT base = calend2baseT(t0);
    return baseT2sow(base);
}

TimeSys::~TimeSys()
{

}

CalendT TimeSys::sow2calend(SOW t0)
{
    BaseT base = sow2baseT(t0);
    return baseT2calend(base);
}

bool TimeSys::compare(SOW t1, SOW t2)
{
	return false;
}

bool TimeSys::print_time(CalendT t)
{
	cout << t.year << "年" << t.month << "月" << t.day << "日"
		<< t.hour << "时" << t.min << "分" << t.sec << "秒";
	return true;
}

bool TimeSys::print_time(SOW t)
{
    cout << "周: " << t.week<< " 秒: " << t.sec<< " 小数秒: " << t.sesec <<endl<<endl;
    return true;
}

BaseT TimeSys::sow2baseT(SOW t0) {
    BaseT t = calend2baseT(this->originT);
    // 以 1970-01-01 为原点，直接计算总秒数
    t.sec = (time_t)t0.week * 7 * 86400 + t0.sec;
    t.sesec = t0.sesec;
    return t;
}
BaseT TimeSys::calend2baseT(CalendT t0) {
    const int doy[] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
    BaseT baseT = { 0, 0.0 };
    int days, sec, year = t0.year, mon = t0.month, day = t0.day;
    // 检查年份和月份的有效性
    if (year < 1970 || year > 2099 || mon < 1 || mon > 12) {
        return baseT;
    }
    // 计算从 1970-01-01 到 t0 的天数
    days = (year - 1970) * 365 + (year - 1969) / 4 + doy[mon - 1] + day - 2;
    if (year % 4 == 0 && mon >= 3) {
        days += 1; // 闰年并且月份大于等于3月
    }
    // 计算当天的秒数
    sec = t0.hour * 3600 + t0.min * 60 + t0.sec;
    // 填充 BaseT 结构
    baseT.sec = (time_t)days * 86400 + sec;
    baseT.sesec = t0.sesec;
    return baseT;
}

SOW TimeSys::baseT2sow(BaseT t) {
    SOW sow;
    // 以 originT 为原点，先获得原点的 BaseT
    BaseT t0 = calend2baseT(this->originT);
    time_t sec = t.sec - t0.sec;
    int week = static_cast<int>(sec / (7 * 86400)); /*static_cast C++提供的更安全的强制类型转换*/
    sow.week = week;
    sow.sec = static_cast<int>(sec - week * 7 * 86400);
    sow.sesec = t.sesec;
    return sow;
}

CalendT TimeSys::baseT2calend(BaseT t) {
    CalendT c = originT;
    // 计算自 originT 起的总秒数
    time_t sec = t.sec;
    // 先加天数
    int days = static_cast<int>(sec / 86400);
    int rem = static_cast<int>(sec % 86400);
    // 处理天数
    while (days > 0) {
        int mdays = month_days(c.year, c.month);
        if (c.day < mdays) {
            int d = std::min(mdays - c.day, days);
            c.day += d;
            days -= d;
            if (c.day == mdays) {
                c.day = 1;
                c.month++;
                if (c.month > 12) {
                    c.month = 1;
                    c.year++;
                }
            }
        } else {
            c.day = 1;
            c.month++;
            if (c.month > 12) {
                c.month = 1;
                c.year++;
            }
            days--;
        }
    }
    // 处理时分秒
    c.hour = rem / 3600;
    c.min = (rem % 3600) / 60;
    c.sec = rem % 60;
    c.sesec = t.sesec;
    return c;
}

double TimeSys::time_minus(BaseT t1, BaseT t2) {
    return static_cast<double>(t1.sec - t2.sec) + (t1.sesec - t2.sesec);
}

BaseT TimeSys::str2baseT(string t) {
	CalendT t1 = str2calendT(t);
    return calend2baseT(t1);
}

CalendT TimeSys::str2calendT(string t)
{
    CalendT cal = { 0 };
    double sesec = 0.0;
    // 解析格式: 年 月 日 时 分 秒.小数
    int n = sscanf_s(t.c_str(), "%d %d %d %d %d %lf",
        &cal.year, &cal.month, &cal.day,
        &cal.hour, &cal.min, &sesec);
    if (n < 6) return { 0 };
    cal.sec = static_cast<int>(sesec);
    cal.sesec = sesec - cal.sec;
    return cal;
}

